﻿using System;
using System.Linq;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using Adalbertus.BudgetPlanner.Domain;
using Adalbertus.BudgetPlanner.Services;
using Caliburn.Micro;
using Adalbertus.BudgetPlanner.ViewModels.ExternalSources;

namespace Adalbertus.BudgetPlanner.ViewModels.BudgetPlanning
{
    public class BudgetPlanViewModel : Screen
    {
        private IBudgetService _budgetService;
        private IBudgetPlanService _budgetPlanService;
        public BudgetPlanViewModel(IBudgetService budgetService, IBudgetPlanService budgetPlanService)
        {
            Contract.Requires<ArgumentNullException>(budgetService != null);

            _budgetService = budgetService;
            _budgetPlanService = budgetPlanService;

            RevenuesViewModel = IoC.Get<RevenuesViewModel>();
            ExpensesViewModel = IoC.Get<ExpensesViewModel>();
            //TODO: ConductWith doesn't work - it must be used mannually from OnActivate and Deactivate methods
            //RevenuesViewModel.ConductWith(this);
        }

        protected override void OnActivate()
        {
            base.OnActivate();

            if (RevenuesViewModel!=null)
            {
                RevenuesViewModel.Budget = Budget;
                (RevenuesViewModel as IActivate).Activate();
            }
            if (ExpensesViewModel != null)
            {
                ExpensesViewModel.Budget = Budget;
                (ExpensesViewModel as IActivate).Activate();
            }
        }

        protected override void OnDeactivate(bool close)
        {
            base.OnDeactivate(close);
            if (RevenuesViewModel!=null)
            {
                (RevenuesViewModel as IDeactivate).Deactivate(close);
            }
            if (ExpensesViewModel != null)
            {
                (ExpensesViewModel as IDeactivate).Deactivate(close);
            }
        }

        public RevenuesViewModel RevenuesViewModel { get; set; }
        public ExpensesViewModel ExpensesViewModel { get; set; }

        #region Budget
        private BudgetVM _budget = null;
        public BudgetVM Budget
        {
            get
            {
                //Contract.Ensures(Contract.Result<BudgetVM>() != null);
                return _budget;
            }
            set
            {
                Contract.Requires<ArgumentNullException>(value != null);
                if (_budget != null)
                {
                    _budget.PropertyChanged -= BudgetPropertyChanged;
                }
                _budget = value;
                _budget.PropertyChanged += BudgetPropertyChanged;

                NotifyOfPropertyChange(() => Budget);
            }
        }

        public DateTime DateFrom
        {
            get { return Budget.DateFrom; }
            set { Budget.DateFrom = value; }
        }

        public DateTime DateTo
        {
            get { return Budget.DateTo; }
            set { Budget.DateTo = value; }
        }

        private void LoadCurrentBudget()
        {
            Budget budget = _budgetService.GetBudgetByDate(DateTime.Now);

            Budget = new BudgetVM(budget);
            Budget.PropertyChanged += BudgetPropertyChanged;
        }

        private void BudgetPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Revenues":
                    //TODO: implement optimal saving!
                    SaveRevenues();
                    break;
                case "DateFrom":
                case "DateTo":
                    //TODO: implement optimal saving!
                    SaveWholeBudget();
                    break;
                case "PlanList":
                    //TODO: implement optimal saving!
                    SaveWholeBudget();
                    break;
            }
        }
        private void SaveWholeBudget()
        {
            Domain.Budget budgetToSave = Budget.WrappedBudget;
            _budgetService.Save(Budget.WrappedBudget);
        }
        #endregion Budget


        private void SaveRevenues()
        {
            SaveWholeBudget();
        }


        public void CreateNewBudgetPlan()
        {
            Domain.Budget draftedBudget = _budgetService.GetDraftedBudget();
            if (draftedBudget == null)
            {
                draftedBudget = _budgetService.GenerateEmptyBudgetForNextMonth(DateTime.Now);
            }

            Budget = new BudgetVM(draftedBudget);
        }

        public void RemoveIncomeEntry(IncomeEntryVM incomeEntry)
        {
            // TODO: I guess it is a bug in caliburn - this method is invoked not from BudgetPlanView
            // but from RevenuesView, unfortunatelly caliburn think it was invoked from BudgetPlanView
            Contract.Requires<ArgumentNullException>(incomeEntry != null, "incomeEntry");
            RevenuesViewModel.RemoveIncomeEntry(incomeEntry);
        }

        public void RemoveSavingEntry(SavingEntryVM savingEntry)
        {
            // TODO: I guess it is a bug in caliburn - this method is invoked not from BudgetPlanView
            // but from RevenuesView, unfortunatelly caliburn think it was invoked from BudgetPlanView
            Contract.Requires<ArgumentNullException>(savingEntry != null, "savingEntry");
            RevenuesViewModel.RemoveSavingEntry(savingEntry);
        }

        public void RemoveExpenseValueFromCalculator(decimal value)
        {
            // TODO: I guess it is a bug in caliburn - this method is invoked not from BudgetPlanView
            // but from ExpensesView, unfortunatelly caliburn think it was invoked from BudgetPlanView
            ExpensesViewModel.RemoveExpenseValueFromCalculator(value);
        }

        #region BudgetPlan
        public BindableCollectionExt<BudgetPlanVM> BudgetPlanList
        {
            get { return Budget.PlanList; }
        }

        private BudgetPlanVM _selectedBudgetPlan;
        public BudgetPlanVM SelectedBudgetPlan
        {
            get { return _selectedBudgetPlan; }
            set
            {
                if (_selectedBudgetPlan != null)
                {
                    _selectedBudgetPlan.PropertyChanged -= SelectedBudgetPlanPropertyChanged;
                }

                _selectedBudgetPlan = value;
                if (_selectedBudgetPlan != null)
                {
                    _selectedBudgetPlan.PropertyChanged += SelectedBudgetPlanPropertyChanged;
                    //_selectedBudgetPlan.DetailRemoved += new EventHandler(_selectedBudgetPlan_DetailRemoved);
                }
                _selectedBudgetPlan.SetDefaultFocus();
                NotifyOfPropertyChange(() => SelectedBudgetPlan);
                NotifyOfPropertyChange(() => CanAddPlanDetailItem);
            }
        }

        //void _selectedBudgetPlan_DetailRemoved(object sender, EventArgs e)
        //{
        //    if (sender is BudgetPlanDetailVM)
        //    {
        //        _budgetPlanService.RemoveDetail((sender as BudgetPlanDetailVM).WrappedBudgetPlanDetail);
        //    }
        //}

        private void SelectedBudgetPlanPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "CanAddDetail":
                    NotifyOfPropertyChange(() => CanAddPlanDetailItem);
                    break;
                case "Details":
                    SaveBudgetPlan(SelectedBudgetPlan);
                    break;
            }
        }

        public bool CanAddPlanDetailItem
        {
            get
            {
                if (SelectedBudgetPlan == null)
                {
                    return false;
                }

                return SelectedBudgetPlan.CanAddDetail;
            }
        }

        public void AddPlanDetailItem()
        {
            if (SelectedBudgetPlan == null)
            {
                return;
            }

            SelectedBudgetPlan.AddDetail();
        }

        private void SaveBudgetPlan(BudgetPlanVM budgetPlan)
        {
            Contract.Requires<ArgumentNullException>(budgetPlan != null, "budgetPlan");
            _budgetPlanService.Save(budgetPlan.WrappedBudgetPlan);
        }
        #endregion
    }
}
